#include "preHeader.h"
#include "Object.h"

Object::Object(OBJECT_TYPE objType)
: m_objType(objType)
, m_guid(ObjGUID_NULL)
{
	m_bitMask32.Resize(objValuesCount[objType]);
	m_s32Values = new s32[m_bitMask32.Size()]();
	m_bitMask64.Resize(obj64ValuesCount[objType]);
	m_s64Values = new s64[m_bitMask64.Size()]();
}

Object::~Object()
{
	delete[] m_s32Values;
	delete[] m_s64Values;
}

void Object::SetS32Value(size_t index, s32 value)
{
	DBGASSERT(index < m_bitMask32.Size());
	if (m_s32Values[index] == value) {
		return;
	}

	m_s32Values[index] = value;
	m_bitMask32.SetDirty(index);
}

void Object::SetF32Value(size_t index, f32 value)
{
	DBGASSERT(index < m_bitMask32.Size());
	if (m_f32Values[index] == value) {
		return;
	}

	m_f32Values[index] = value;
	m_bitMask32.SetDirty(index);
}

void Object::ModS32Value(size_t index, s32 value)
{
	DBGASSERT(index < m_bitMask32.Size());
	if (value == 0) {
		return;
	}

	auto oldValue = m_s32Values[index];
	auto newValue = oldValue + value;
	if (value < 0) {
		if (newValue < oldValue) {
			m_s32Values[index] = newValue;
		} else {
			m_s32Values[index] = INT32_MIN;
		}
	} else {
		if (newValue > oldValue) {
			m_s32Values[index] = newValue;
		} else {
			m_s32Values[index] = INT32_MAX;
		}
	}
	m_bitMask32.SetDirty(index);
}

void Object::ModF32Value(size_t index, f32 value)
{
	DBGASSERT(index < m_bitMask32.Size());
	if (value == 0) {
		return;
	}

	m_f32Values[index] += value;
	m_bitMask32.SetDirty(index);
}

void Object::SetS64Value(size_t index, s64 value)
{
	DBGASSERT(index < m_bitMask64.Size());
	if (m_s64Values[index] == value) {
		return;
	}

	m_s64Values[index] = value;
	m_bitMask64.SetDirty(index);
}

void Object::SetF64Value(size_t index, f64 value)
{
	DBGASSERT(index < m_bitMask64.Size());
	if (m_f64Values[index] == value) {
		return;
	}

	m_f64Values[index] = value;
	m_bitMask64.SetDirty(index);
}

void Object::ModS64Value(size_t index, s64 value)
{
	DBGASSERT(index < m_bitMask64.Size());
	if (value == 0) {
		return;
	}

	auto oldValue = m_s64Values[index];
	auto newValue = oldValue + value;
	if (value < 0) {
		if (newValue < oldValue) {
			m_s64Values[index] = newValue;
		} else {
			m_s64Values[index] = INT64_MIN;
		}
	} else {
		if (newValue > oldValue) {
			m_s64Values[index] = newValue;
		} else {
			m_s64Values[index] = INT64_MAX;
		}
	}
	m_bitMask64.SetDirty(index);
}

void Object::ModF64Value(size_t index, f64 value)
{
	DBGASSERT(index < m_bitMask64.Size());
	if (value == 0) {
		return;
	}

	m_f64Values[index] += value;
	m_bitMask64.SetDirty(index);
}

void Object::SetFlag(size_t index, uint32 flag)
{
	DBGASSERT(index < m_bitMask32.Size());
	if ((m_s32Values[index] & flag) == flag) {
		return;
	}

	m_s32Values[index] |= flag;
	m_bitMask32.SetDirty(index);
}

void Object::RemoveFlag(size_t index, uint32 flag)
{
	DBGASSERT(index < m_bitMask32.Size());
	if ((m_s32Values[index] & flag) == 0) {
		return;
	}

	m_s32Values[index] &= ~flag;
	m_bitMask32.SetDirty(index);
}

bool Object::HasFlag(size_t index, uint32 flag) const
{
	DBGASSERT(index < m_bitMask32.Size());
	return (m_s32Values[index] & flag) == flag;
}

bool Object::HasOneOfFlag(size_t index, uint32 flags) const
{
	DBGASSERT(index < m_bitMask32.Size());
	return (m_s32Values[index] & flags) != 0;
}

void Object::BuildCreatePacketForPlayer(INetPacket& pck, Player* pPlayer)
{
	pck << m_guid;
	for (size_t i = 0, n = m_bitMask32.Size(); i < n; ++i) {
		pck << m_s32Values[i];
	}
	for (size_t i = 0, n = m_bitMask64.Size(); i < n; ++i) {
		pck << m_s64Values[i];
	}
}

void Object::BuildValue32UpdatePacket(INetPacket& pck) const
{
	m_bitMask32.Write(pck);
	auto pos = m_bitMask32.FindFirst();
	for (; pos != CBitMask::npos; pos = m_bitMask32.FindNext(pos)) {
		pck << m_s32Values[pos];
	}
}

void Object::BuildValue64UpdatePacket(INetPacket& pck) const
{
	m_bitMask64.Write(pck);
	auto pos = m_bitMask64.FindFirst();
	for (; pos != CBitMask::npos; pos = m_bitMask64.FindNext(pos)) {
		pck << m_s64Values[pos];
	}
}
